<?php

declare(strict_types=1);

namespace App\CustHub\Service;

use App\CustHub\Event\ContactBlackListAddAfter;
use App\CustHub\Mapper\ChContactBlackMapper;
use App\CustHub\Mapper\ChContactBwDeleteRecordMapper;
use App\CustHub\Mapper\ChRoomMemberMapper;
use App\CustHub\Model\ChContact;
use App\CustHub\Model\ChContactBlack;
use App\CustHub\Model\ChContactBwDeleteRecord;
use App\CustHub\Model\ChRoomMember;
use Carbon\Carbon;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Mine\Abstracts\AbstractService;
use Mine\Annotation\Transaction;
use Mine\Exception\NormalStatusException;
use Mine\MineModel;
use Psr\EventDispatcher\EventDispatcherInterface;
use function Hyperf\Collection\collect;
use function Hyperf\Collection\data_get;
use function Hyperf\Coroutine\co;

/**
 * 客户黑名单
 */
class ChContactBlackService extends AbstractService
{
    public $mapper;

    #[Inject]
    protected EventDispatcherInterface $eventDispatcher;

    #[Inject]
    protected ChContactBwDeleteRecordMapper $bwDeleteRecordMapper;

    public function __construct(ChContactBlackMapper $mapper)
    {
        $this->mapper = $mapper;
    }

    public function list(array $data): array
    {
        $pageSize = data_get($data, 'page_size', MineModel::PAGE_SIZE);
        $page = data_get($data, 'page', 1);

        $keyword = data_get($data, 'keyword');

        $firstQuery = Db::table('ch_contact_black as a')
            ->selectRaw('a.id, a.user_id, b.nickname, b.avatar, b.is_wechat, b.corp_id, b.corp_short_name as corp_name, "contact" as source,a.created_at')
            ->join('ch_contact as b', 'a.user_id', '=', 'b.user_id')
            ->where('a.main_uid', $data['main_uid'])
            ->when(!empty($data['trigger_start_time']) && !empty($data['trigger_end_time']), function ($query) use ($data) {
                $query->whereBetween('a.trigger_time', [$data['trigger_start_time'], $data['trigger_end_time']]);
            })
            ->when(!empty($data['add_start_time']) && !empty($data['add_end_time']), function ($query) use ($data) {
                $query->whereBetween('a.created_at', [$data['add_start_time'], $data['add_end_time']]);
            })
            ->when(!empty($keyword), function ($query) use ($keyword) {
                if (is_numeric($keyword)) {
                    $query->where('a.user_id', $keyword);
                } else {
                    $query->where('b.nickname', 'like', '%' . $keyword . '%');
                }
            });

        $sql = Db::table('ch_contact_black as a')
            ->selectRaw('a.id, a.user_id, b.nickname, b.avatar, b.member_type as is_wechat, b.corp_id, b.corp_name, "room_member" as source,a.created_at')
            ->join('ch_room_member as b', 'a.user_id', '=', 'b.user_id')
            ->where('a.main_uid', $data['main_uid'])
            ->when(!empty($data['trigger_start_time']) && !empty($data['trigger_end_time']), function ($query) use ($data) {
                $query->whereBetween('a.trigger_time', [$data['trigger_start_time'], $data['trigger_end_time']]);
            })
            ->when(!empty($data['add_start_time']) && !empty($data['add_end_time']), function ($query) use ($data) {
                $query->whereBetween('a.created_at', [$data['add_start_time'], $data['add_end_time']]);
            })
            ->when(!empty($keyword), function ($query) use ($keyword) {
                if (is_numeric($keyword)) {
                    $query->where('a.user_id', $keyword);
                } else {
                    $query->where('b.nickname', 'like', '%' . $keyword . '%');
                }
            })->union($firstQuery)->toRawSql();

        $fullSql = "SELECT * FROM ($sql) as union_table GROUP BY user_id ORDER BY created_at DESC";

        $total = Db::select("SELECT COUNT(*) as count FROM ($sql) as union_table GROUP BY user_id");
        $total = count($total);

        $items = Db::select($fullSql . " LIMIT " . (($page - 1) * $pageSize) . ", " . $pageSize);

        // 创建分页对象
        $list = new \Hyperf\Paginator\LengthAwarePaginator(
            $items,
            $total,
            (int)$pageSize,
            (int)$page,
        );

        return $this->mapper->setPaginate($list);
    }


    /**
     * 加入黑名单
     * @param array $data
     * @return bool
     */
    #[Transaction]
    public function saveBlack(array $data,bool $isNeedTrigger = true): bool
    {
        if(is_array($data['user_ids'])){
            $userIds = $data['user_ids'];
        }else{
            $userIds = json_decode($data['user_ids'], true);
        }

        $mainUid = $data['main_uid'];
        $existingContactMap = ChContactBlack::query()
            ->where('main_uid',$mainUid)
            ->whereIn('user_id', $userIds)
            ->pluck('id', 'user_id');

        $toInsertUserIds = collect($userIds)->reject(fn($item) => $existingContactMap->has($item))->toArray();

        $toInsert = [];

        foreach ($toInsertUserIds as $userId) {
            $toInsert[] = [
                'uid' => $data['uid'],
                'main_uid' => $mainUid,
                'user_id' => $userId,
                'add_type' => $data['add_type'] ?? 1, // 手动添加
                'trigger_time' => Carbon::now()->toDateTimeString()
            ];
        }

        if (empty($toInsert)) {
            return true;
        }

        $rst = $this->batchSave($toInsert);

        ChContact::query()
            ->where('main_uid', $mainUid)
            ->whereIn('user_id', $toInsertUserIds)
            ->update(['is_black' => 1]);

        ChRoomMember::query()
            ->whereIn('user_id', $toInsertUserIds)
            ->whereHas('room', function ($query) use ($mainUid) {
                $query->where('main_uid', $mainUid);
            })
            ->update(['is_black' => 1]);

        if($isNeedTrigger){
            co(function () use ($mainUid,$toInsertUserIds) {
                $this->eventDispatcher->dispatch(new ContactBlackListAddAfter($mainUid,$toInsertUserIds));
            });
        }
        return $rst;
    }


    /**
     * 删除黑名单
     * @param array $data
     * @return bool
     * @throws \Exception
     */
    #[Transaction]
    public function deleteBlack(array $data): bool
    {
        $ids = json_decode($data['ids'], true);
        $this->del($data['main_uid'],$ids);
        return true;
    }

    /**
     * 清空黑名单
     * @param array $data
     * @return bool
     */
    #[Transaction]
    public function clear(array $data): bool
    {
        $this->del($data['main_uid']);
        return true;
    }


    private function del(mixed $mainUid, array $ids = []): bool
    {
        $list = $this->mapper->model::query()
            ->when(!empty($ids),function ($query) use ($ids){
                $query->whereIn('id', $ids);
            })
            ->where('main_uid', $mainUid)
            ->get();

        if($list->isEmpty()){
            return true;
        }

        $recordData = [];
        $userIds = [];
        foreach ($list as $info) {
            $userIds[] = $info->user_id;
            $recordData[] = [
                'uid' => $info->uid,
                'main_uid' => $info->main_uid,
                'user_id' => $info->user_id,
                'join_time' => $info->created_at,
                'delete_time' => Carbon::now()->toDateTimeString()
            ];
        }

        // 删除黑名单
        $this->mapper->model::query()
            ->when(!empty($ids),function ($query) use ($ids){
                $query->whereIn('id', $ids);
            })
            ->where('main_uid', $mainUid)
            ->delete();

        //更新客户黑明单状态
        ChContact::query()
            ->whereIn('user_id',$userIds)
            ->update([
                'is_black' => 0
            ]);

        ChRoomMember::query()
            ->whereIn('user_id', $userIds)
            ->update(['is_black' => 0]);

        // 添加删除记录
        $this->bwDeleteRecordMapper->model::insert($recordData);
        return true;
    }
}